home *** CD-ROM | disk | FTP | other *** search
- ; Status byte definition (C_Status):
-
- ; 7 6 5 4 3 2 1 0
- ; | | | | | | | |____ Input buffer empty
- ; | | | | | | |________ Input buffer full
- ; | | | | | |____________ Output buffer empty
- ; | | | | |________________ Output buffer full
- ; | | | |____________________ Input buffer overflow
- ; | | |________________________ Output buffer overflow
- ; | |____________________________ Hard handshake active (xmit stopped)
- ; |________________________________ Soft handshake active (xmit stopped)
-
- ; Control byte definition (C_Ctrl):
-
- ; 7 6 5 4 3 2 1 0
- ; | | | | | | | |____ Enable RTS handshake
- ; | | | | | | |________ Enable CTS handshake
- ; | | | | | |____________ Enable software handshake
- ; | | | | |________________
- ; | | | |____________________
- ; | | |________________________
- ; | |____________________________
- ; |________________________________
-
- ;********************************************************
-
- ; Macro: PutChar
- ; Function: Place character in transmit buffer (transmit a character)
- ; Entry: AL <- Port # (0-3)
- ; AH <- Status register
- ; BX <- Byte array pointer
- ; CH <- Character to put in buffer
- ; DX <- Base address of port
- ; Destroyed: ES,SI,DI,AL
-
- ; Note: Port address passed is NOT checked for validity.
- ; Subroutine ChkPort will create the proper entry environment
-
- PUTCHAR MACRO
-
- test ah, 00001000b ;Is buffer full?
- JZ @@putch1 ;No, OK to put character
- or ah, 00100000b ;set overflow flag
- JMP @@putchx ;and exit
-
- @@putch1:
- shl bl,1 ;bx <- word array index
- mov di, [C_outhead+bx] ;bump the head pointer
- mov si, [c_outtail+bx]
- inc di
- cmp di, [C_outsize+bx]
- jb @@putch2
- xor di,di
- @@putch2:
- mov [C_outhead+bx],di ;save head pointer
- inc [C_buffull+bx] ;increment buffer-full word
-
- shl bl,1 ;BX <- pointer array index
- LES BX, [C_outbufptr+bx] ;Load ES with segment of output buf
- mov [ES:BX+DI],ch ;save the byte
-
- cmp di, si ;Is output buffer full?
- jnz @@putch3 ;no, go enable xmitter
- or ah, 00001000b ;Set status to output buffer full
- @@putch3:
- xor bh, bh
- mov bl, al ;Save AL in BL and make BX byte index
-
- test ah, 11000000b ;soft/hard handshake on?
- jnz @@putchx
- ; test ah, 00000100b
- ; jz @@putchx
-
- and ah, 11111011b ;Buffer is no longer empty
- inc dl ;Change to IER register
- in al, dx ;Read in the IER
- or al, 00000010b ;Turn on xmt interrupt
- NOP ;Slow down for slow machines
- NOP
- out dx, al ;Write out the IER
- dec dl ;Back to base reg
- @@putchx:
- mov [C_status+bx],ah ;set status byte
- ; mov al,bl ;get port num back in AL
- ENDM
-
- ;******************************************************************
- ; MACRO: Test for modem status change
- ;
- ; Entry: DX - port base
- ; BX - byte array index
- ;
- ; Destroyed: AX, CX
-
- MSCHG MACRO
-
- ; Get modem status & control/status registers
-
- @@Msc0: ADD DL,MSR ;DX <- 8250 MSR port address
- IN AL,DX ;AL <- 8250 Modem status
- SUB DL,MSR ;Back to base
-
- MOV CL,[C_Status+BX] ;CL <- Status register
- MOV CH,[C_Ctrl+BX] ;CH <- Control register
-
- ; Control CTS status flag based on CTS status and handshake enable
-
- TEST CH,00000010b ;CTS handshake enabled ?
- JZ @@Msc2 ; No, ignore CTS status
- TEST AL,00010000b ;CTS asserted ?
- JNZ @@Msc1 ; Yes, enable transmit
- OR CL,01000000b ;CTS inactive - hard handshake on
- JMP @@Msc2 ;
- @@Msc1: AND CL,10111111b ;CTS active - hard handshake off
- @@Msc2: MOV [C_Status+BX],CL ;Save status flags
-
- ; Determine if transmitter should be enabled
-
- @@Msc3: ADD DL,IER ;DX <- 8250 IER port address
- IN AL,DX ;AL <- Interrupt enable register
- OR AL,00000010b ;Enable transmitter by default
- TEST CL,11000100b ;Enable transmitter ?
- JZ @@Msc4 ; Yes
- AND AL,11111101b ; No - disable transmitter
- @@Msc4: OUT DX,AL ;Update IER
- SUB DL, IER
-
- ENDM
-
- IDEAL
-
- SEGMENT DATA WORD PUBLIC
-
- ; Externally accessed (TP program) variables
- ; Note: Most of these variables are declared as arrays in the main
- ; program; i.e. C_InSize : Array[1..4] Of Word
-
- EXTRN C_InBufPtr :DWORD ;Pointer to input buffers
- EXTRN C_OutBufPtr:DWORD ;Pointer to output buffers
- EXTRN C_InSize :WORD ;Size (bytes) of input buffers
- EXTRN C_OutSize :WORD ;Size (bytes) of output buffers
- EXTRN C_InHead :WORD ;Input (receive) head pointers
- EXTRN C_OutHead :WORD ;Output (transmit) head pointers
- EXTRN C_InTail :WORD ;Input (receive) tail pointers
- EXTRN C_OutTail :WORD ;Output (transmit) tail pointers
- EXTRN C_RTSOn :WORD ;Point at which RTS line is asserted
- EXTRN C_RTSOff :WORD ;Point at which RTS line is dropped
- EXTRN C_StartChar:BYTE ;Start character for soft handshake
- EXTRN C_StopChar :BYTE ;Stop character for soft handshake
- EXTRN C_Status :BYTE ;Status byte (see above)
- EXTRN C_Ctrl :BYTE ;Control byte (see above)
- EXTRN C_PortOpen :BYTE ;Port-open flags
- EXTRN C_PortAddr :WORD ;Base address of ports
- EXTRN C_MaxCom :BYTE ;Highest port # defined (single byte)
- EXTRN C_bufFull :WORD
- EXTRN C_cascade :BYTE
- ; EXTRN C_CharSend :WORD
- ; EXTRN C_CharWrite :WORD
- ; EXTRN C_Temp :WORD ;Used for debugging
-
- ; 8250 register offsets
-
- IER EQU 1 ;Interrupt enable register
- IIR EQU 2 ;Interrupt identification register
- LCR EQU 3 ;Line control register
- MCR EQU 4 ;Modem control register
- LSR EQU 5 ;Line status register
- MSR EQU 6 ;Modem status register
- SCR EQU 7 ;8250 scratch register
-
- ENDS DATA
-
- ; Code segment declaration
-
- SEGMENT CODE BYTE PUBLIC
-
- ASSUME CS:CODE,DS:DATA
-
- ; Externally accessable procedures defined here
-
- PUBLIC INT_Handler
- PUBLIC ComReadCh
- PUBLIC ComReadChW
- PUBLIC ComWriteCh
- PUBLIC ComWriteChW
-
- ;********************************************************
- ;* *
- ;* Subroutines that are used internally *
- ;* *
- ;********************************************************
-
- ; Subroutine: ChkPort
- ; Function: Check port parameter(s), ensure that port is OPEN
- ; Entry: AL <- Port # (1 - C_MaxCom)
- ; Exit: AL -> Adjusted port # (0 - 3)
- ; AH -> Status register
- ; BX -> Byte array index
- ; DX -> Base address of port
- ; Carry flag SET if parameters & port are OK
- ;
- ; PROC ChkPort FAR
- ;
- ; Determine if port # is valid
- ;
- ; CMP AL,[C_MaxCom] ;Port # > Maximum port # ?
- ; JA ChkErr ; Yes, exit w/error
- ; CMP AL,0 ;Port # = 0 (invalid port #)
- ; JZ ChkErr ; Yes, exit w/error
- ; DEC AL ;AL <- Adjusted port #
- ;
- ; Check if port open
- ;
- ; XOR BH,BH ;
- ; MOV BL,AL ;BX <- Byte array index
- ; MOV AH,[C_PortOpen+BX] ;AH <- Port-open flag
- ; CMP AH,0 ;Port open ?
- ; JZ ChkErr ; No, exit w/error
- ;
- ; Get status register and base port address in DX
- ;
- ; MOV AH,[C_Status+BX] ;AH <- Status register
- ; SHL BL,1 ;BX <- Word array index
- ; MOV DX,[C_PortAddr+BX] ;DX <- Port address
- ; SHR BL,1 ;BX <- Byte array index
- ; STC ;Set carry (valid return)
- ; RET ;Exit
- ;
- ; Here if error
- ;
- ;ChkErr: CLC ;Clear carry (invalid return)
- ; RET ;Exit
- ;
- ; ENDP ChkPort
-
- ; PROC PutChar FAR
- ;
- ;; Check for buffer overflow
- ;
- ; TEST AH,00001000b ;Buffer full ?
- ; JZ PutCh1 ; No, continue
- ; OR AH,00100000b ;Set buffer-overflow flag
- ; JMP PutChX ;Exit
- ;
- ;; Increment head pointer
- ;
- ;PutCh1: SHL BL,1 ;BX <- Word array index
- ; MOV DI,[C_OutHead+BX] ;DI <- Output head pointer
- ; MOV SI,[C_OutTail+BX] ;SI <- Output tail pointer
- ; INC DI ;Bump head pointer
- ; CMP DI,[C_OutSize+BX] ;Head >= Buffer size ?
- ; JB PutCh2 ; No, continue
- ; XOR DI,DI ; Yes, reset pointer
- ;PutCh2: MOV [C_OutHead+BX],DI ;Save head pointer
- ; INC [C_buffull+bx] ;Increment chars in buffer
- ;; INC [C_charwrite+bx]
- ;
- ;; Place character in buffer
- ;
- ; SHL BL,1 ;BX <- Pointer array index
- ; LES BX,[C_OutBufPtr+BX] ;ES:BX <- Pointer to output buffer
- ; MOV [ES:BX+DI],CH ;Place character in buffer
- ;
- ;; Check for full buffer
- ;
- ; CMP DI,SI ;Head = Tail (buffer full) ?
- ; JNZ PutCh3 ; No, buffer not full
- ; OR AH,00001000b ;Set buffer-full flag
- ;
- ;; Determine if transmitter should be activated
- ;
- ;PutCh3: XOR BH,BH ;
- ; MOV BL,AL ;BX <- Byte array index
- ;
- ; TEST AH,11000000b ;Any inhibits (soft/hard hshake) ?
- ; JNZ PutChX ; Yes, do not activate xmit interrupt
- ;; TEST AH,00000100b ;Buffer empty ?
- ;; JZ PutChX ; No, xmit interrupt is on already
- ;
- ; AND AH,11111011b ;Reset buffer-empty flag
- ; ADD DL,IER ;Point to interrupt enable register
- ; IN AL,DX ;AL <- Interrupt enable register
- ; OR AL,00000010b ;Enable transmit interrupt
- ; NOP ;Slow down for slow machines
- ; NOP
- ; OUT DX,AL ;Update port
- ; SUB DL,IER ;Point back to base
- ;
- ;; Here to exit
- ;
- ;PutChX: MOV [C_Status+BX],AH ;Save status byte
- ; MOV AL,BL ;
- ; RET ;Exit
- ;
- ; ENDP PutChar
-
-
- ;********************************************************
- ;* *
- ;* Interrupt service routine for INT3,INT4 *
- ;* *
- ;* INT3 typically used by COM2, COM4 *
- ;* INT4 typically used by COM1, COM3 *
- ;* *
- ;********************************************************
-
- PROC INT_Handler FAR
-
- PUSH AX ;Save environment
- PUSH BX ;
- PUSH CX ;
- PUSH DX ;
- PUSH SI ;
- PUSH DI ;
- PUSH DS ;
- PUSH ES ;
- PUSH BP ;
-
- MASM
- MOV AX,SEG DATA ;AX <- Current data segment
- IDEAL
- MOV DS,AX ;Set new data segment
-
- INT_Id: XOR BX,BX ;BL <- Port # (start at 0)
-
- ; Identify active port
-
- IntID1: MOV AL,[C_PortOpen+BX] ;AL <- Port-open flag
- CMP AL,0 ;Port open ?
- JZ IntID2 ; No, don't check
- SHL BL,1 ;BX <- Word array index
- MOV DX,[C_PortAddr+BX] ;DX <- Base address of port
- SHR BL,1 ;BX <- Byte array index
- ADD DL,IIR ;Add in offset for IIR
- IN AL,DX ;AL <- COMn IIR
- TEST AL,00000001b ;Interrupt active on this port ?
- JZ INT_Active ; (Bit 0 = 0 if active)
- IntID2: INC BL ;Bump port #
- CMP BL,[C_MaxCom] ;All ports checked ?
- JB IntID1 ; No, continue
-
- ; Here to reset 8259 controller
-
- MOV AL,20h ;AL <- EOI Acknowledge code
- OUT 20h,AL ;To 8259 PIC
- MOV AL,[C_Cascade] ;Move cascade flag
- CMP AL,0 ;No cascade?
- JE IntID3 ;Check it no cascaded irq
-
- ; Reset cascade port
-
- MOV DX,0A0h ;DX To 8259 cascade PIC
- MOV AL,20h ;AL <- EOI Acknowledge code
- OUT DX,AL ;To 8259 cascade PIC
-
- ; Here to leave interrupt handler
-
- IntID3: POP BP ;Restore envirionment
- POP ES ;
- POP DS ;
- POP DI ;
- POP SI ;
- POP DX ;
- POP CX ;
- POP BX ;
- POP AX ;
-
- IRET ;Interrupt exit
-
- ; Active port (8250) found.
- ; Determine cause of interrupt and execute appropriate handler.
- ; Upon entry into routine, registers are set as follows:
- ; BX <- Byte array index
- ; DX <- Port address
-
- INT_Active:
- DEC DX ;
- DEC DX ;DX <- Base address of COM port
-
- CMP AL,0 ;IIR = 0 (Modem status change) ?
- JZ ComMsc ; Yes
- CMP AL,2 ;IIR = 2 (Character transmitted) ?
- JZ ComXmt ; Yes
- CMP AL,4 ;IIR = 4 (Character received) ?
- JNZ Next ;
- JMP ComRcv ; Yes
- Next: CMP AL,6 ;IIR = 6 (Line status change) ?
- JZ ComLsc ; Yes
- JMP INT_Id ;Check other ports & exit
-
- ;*******************************************************
- ; Line status change
- ; NOTE: Currently unused
- ;*******************************************************
-
- ComLsc: ADD DL,LSR ;Point to line status register
- IN AL,DX ;Get LSR
-
- ; The following code (which disables then enables the transmit
- ; interrupt) is required to compensate for some "buggy" 8250's and
- ; 8250-emulating gate arrays.
-
- SUB DL,LSR ;Back to base
- ADD DL,IER ;Point to interrupt enable register
- IN AL,DX ;Get IER
- MOV AH,AL ;Save IER
- AND AL,11111101b ;Mask transmit interrupt
- OUT DX,AL ;Send modified to port
- MOV AL,AH ;
- NOP ;slow down for slow machines
- NOP
- OUT DX,AL ;Send original to port
-
- JMP INT_Id ;Exit
-
- ;*******************************************************
- ; Modem status change
- ;*******************************************************
-
- ComMsc: NOP
-
- ; Get modem status & control/status registers
-
- Msc0: ADD DL,MSR ;DX <- 8250 MSR port address
- IN AL,DX ;AL <- 8250 Modem status
- SUB DL,MSR ;Back to base
-
- MOV CL,[C_Status+BX] ;CL <- Status register
- MOV CH,[C_Ctrl+BX] ;CH <- Control register
-
- ; Control CTS status flag based on CTS status and handshake enable
-
- TEST CH,00000010b ;CTS handshake enabled ?
- JZ Msc2 ; No, ignore CTS status
- TEST AL,00010000b ;CTS asserted ?
- JNZ Msc1 ; Yes, enable transmit
- OR CL,01000000b ;CTS inactive - hard handshake on
- JMP Msc2 ;
- Msc1: AND CL,10111111b ;CTS active - hard handshake off
- Msc2: MOV [C_Status+BX],CL ;Save status flags
-
- ; Determine if transmitter should be enabled
-
- Msc3: ADD DL,IER ;DX <- 8250 IER port address
- IN AL,DX ;AL <- Interrupt enable register
- OR AL,00000010b ;Enable transmitter by default
- TEST CL,11000100b ;Enable transmitter ?
- JZ Msc4 ; Yes
- AND AL,11111101b ; No - disable transmitter
- Msc4: OUT DX,AL ;Update IER
- JMP INT_Id ;Exit
-
- ;*******************************************************
- ; Character transmitted
- ;*******************************************************
-
- ; Register usage:
- ; AH : Status register
- ; BX : Array pointer
- ; DX : Port address
- ; SI : Output tail pointer
- ; DI : Output head pointer
-
- ; Get status and control registers
-
- ComXmt: MOV AH,[C_Status+BX] ;AH <- Status register
- TEST AH,00000100b ;Buffer empty ?
- JNZ Xmt2 ; Yes, stop transmitter
-
- ; Bump tail pointer
-
- PUSH BX ;Save byte array pointer
- SHL BL,1 ;BX <- Word array pointer
- MOV SI,[C_OutTail+BX] ;SI <- Output tail pointer
- MOV DI,[C_OutHead+BX] ;DI <- Output head pointer
-
- INC SI ;Bump tail pointer
- CMP SI,[C_OutSize+BX] ;Tail < Buffer size ?
- JB Xmt1 ; Yes, proceed normally
- XOR SI,SI ; No, reset to 0
- Xmt1: MOV [C_OutTail+BX],SI ;Save tail pointer
-
- DEC [C_buffull+bx] ;Decrement chars in buffer
- ; INC [C_charsend+bx]
-
- ; Send character
-
- SHL BL,1 ;BX <- Pointer array pointer
- LES BX,[C_OutBufPtr+BX] ;ES:BX <- Pointer to output buffer
- MOV AL,[ES:BX+SI] ;AL <- Character from buffer
- OUT DX,AL ;Send
- POP BX ;Recover byte array pointer
-
- ; Determine if buffer is empty
- ; Reset output-buffer-full flag & exit
-
- CMP DI,SI ;Head = Tail (buffer empty) ?
- JNZ Xmt2 ; No, continue normally
- OR AH,00000100b ;Set buffer-empty flag
- Xmt2: AND AH,11010111b ;Reset FULL and OVERFLOW flags
- MOV [C_Status+BX],AH ;Save status flags
- JMP Msc0 ;Exit (check xmit mask)
-
- ;*******************************************************
- ; Character received
- ;*******************************************************
-
- ; Register usage:
- ; AL : Status register
- ; AH : Control register
- ; BX : Array index
- ; CL : Character received
- ; CH : Temporary storage
- ; DX : Port address
- ; SI : Input tail pointer
- ; DI : Input head pointer
-
- ComRcv: IN AL,DX ;
- MOV CL,AL ;CL <- Received character
-
- ; Check for software handshake
-
- MOV AL,[C_Status+BX] ;AL <- Status byte
- MOV AH,[C_Ctrl+BX] ;AH <- Control byte
- TEST AH,00000100b ;Software handshake enabled ?
- JZ Rcv3 ; No, don't check software handshake
- CMP CL,[C_StopChar+BX] ;STOP TRANSMIT character ?
- JZ Rcv1 ; Yes
- CMP CL,[C_StartChar+BX] ;START TRANSMIT character ?
- JNZ Rcv3 ; No
-
- ; Soft-handshake character received.
- ; Activate or deactive transmitter depending on status
-
- AND AL,01111111b ;Reset soft-handshake flag (start)
- JMP Rcv2 ;Save status & exit
- Rcv1: OR AL,10000000b ;Set soft-handshake flag (stop)
- Rcv2: MOV CL,AL ;Routines in MSC2 require status in CL
- JMP Msc2 ;Exit (xmit interrupt controlled here)
-
- ; Clear buffer empty flag / check for buffer overflow
-
-
- Rcv3: AND AL,11111110b ;Clear buffer-empty flag
- TEST AL,00000010b ;Buffer full ?
- JZ Rcv4 ; No, continue
- OR AL,00010000b ;Set overflow flag
- JMP Rcv10 ;Exit
-
- ; Bump receive buffer pointer
-
- Rcv4: SHL BL,1 ;BX <- Word array index
- MOV DI,[C_InHead+BX] ;DI <- Input head pointer
- MOV SI,[C_InTail+BX] ;SI <- Input tail pointer
-
- INC DI ;Bump buffer pointer
- CMP DI,[C_InSize+BX] ;Head > buffer size ?
- JB Rcv5 ; No, continue
- XOR DI,DI ; Yes, reset pointer
-
- ; Store character in buffer
-
- Rcv5: PUSH BX ;Save word array pointer
- MOV [C_InHead+BX],DI ;Save updated input head pointer
- SHL BL,1 ;BX <- Doubleword array index
- LES BX,[C_InBufPtr+BX] ;ES:BX <- Pointer to buffer
- MOV [ES:BX+DI],CL ;Save character in buffer
- POP BX ;Recover word array pointer
-
- ; Check for full buffer
-
- CMP SI,DI ;Tail = Head ?
- JNZ Rcv6 ;If Tail <> Head, buffer is not full
- OR AL,00000010b ;Set buffer-full flag
- JMP Rcv8 ;Reset RTS and exit
-
- ; Check for near-full buffer (buffer used >= RTSOff)
-
- Rcv6: CMP SI,DI ;Tail <= Head ?
- JBE Rcv7 ; Yes, use standard formula
- SUB SI,DI ;SI <- Tail - Head
- MOV DI,[C_InSize+BX] ;DI <- Input buffer size
- Rcv7: SUB DI,SI ;DI <- Head - Tail (amt used)
- CMP DI,[C_RTSOff+BX] ;Used < Limit ?
- JB Rcv9 ; Yes, leave RTS on
-
- ; Buffer is (near) full, force RTS off & exit
-
- Rcv8: TEST AH,00000001b ;RTS handshake enabled ?
- JZ Rcv9 ; No, exit now
-
- MOV CH,AL ;Keep status byte
- ADD DL,MCR ;DX <- Address of modem control reg.
- IN AL,DX ;AL <- MCR
- AND AL,11111101b ;Disable RTS
- OUT DX,AL ;Update MCR
- SUB DL,MCR ;DX <- Base of port
- MOV AL,CH ;Recover status byte
-
- ; Exit - receive
-
- Rcv9: SHR BL,1 ;BX <- Byte array index
- Rcv10: MOV [C_Status+BX],AL ;Save status byte
-
- ; The following code corrects a "bug" present in some 8250's
-
- ADD DL,IER ;DX <- Interrupt Enable Register
- IN AL,DX ;AL <- IER
- MOV AH,AL ;Save IER
- AND AL,11111101b ;Mask off transmit interrupt
- OUT DX,AL ;Send to IER
- MOV AL,AH ;
- NOP ;Slow down for slow machines
- NOP
- OUT DX,AL ;Restore original IER state
-
- JMP INT_Id ;Check for pending INTs and exit
-
- ENDP INT_Handler
-
- ;********************************************************
- ;* *
- ;* Start of Pascal low-level procedures *
- ;* *
- ;********************************************************
- ;* *
- ;* Function ComReadCh(ComPort:Byte) : Char *
- ;* *
- ;********************************************************
-
- PROC ComReadCh FAR
-
- CLI ;Interrupts disabled
-
- MOV BX,SP ;BX <- Stack pointer
- MOV AL,[SS:BX+4] ;AL <- Port #
-
- dec al ;Adjust port number (COM1=0)
- xor bh,bh ;Nuke BH
- mov bl,al ;Get byte index into BL
- shl bl,1 ;Convert to word index
- mov dx,[C_Portaddr+BX] ;Get port base address
- shr bl,1 ;Convert back to byte index
-
- ; Check buffer, return null if empty
-
- MOV AH,[C_Status+BX] ;AH <- Status byte
- TEST AH,00000001b ;Buffer empty ?
- JZ ComRd2 ; No, continue normally
-
- ; Buffer empty, port not open or port # invalid - exit
-
- ComRd1: MOV CH,0 ;Return null (port error or empty)
- ComRdX: MOV AL,CH ;AL <- Char from buffer
- STI ;Enable interrupts
- RET 2 ;Exit
-
- ; Increment tail pointer
- ; NOTE: Entry point for ComReadChW
-
- ComRd2: SHL BL,1 ;BX <- Word array index
- MOV SI,[C_InTail+BX] ;SI <- Tail pointer
- MOV DI,[C_InHead+BX] ;DI <- Input head pointer
- INC SI ;Bump tail pointer
- CMP SI,[C_InSize+BX] ;Tail past end of buffer ?
- JB ComRd3 ; No, continue
- XOR SI,SI ; Yes, reset pointer
- ComRd3: MOV [C_InTail+BX],SI ;Save updated tail pointer
-
- ; Get character from buffer
-
- SHL BL,1 ;BX <- Pointer array index
- LES BX,[C_InBufPtr+BX] ;ES:BX <- Pointer to input buffer
- MOV CH,[ES:BX+SI] ;CH <- Character from buffer
-
- ; Clear FULL and OVERFLOW flags
- ; Check for empty buffer
-
- XOR BH,BH ;
- MOV BL,AL ;Byte array index
- AND AH,11101101b ;Reset FULL and OVERFLOW status flags
- CMP DI,SI ;Head = Tail (buffer empty ?)
- JNZ ComRd4 ; No, continue normally
- OR AH,00000001b ; Yes, set empty flag
- ComRd4: MOV [C_Status+BX],AH ;Save status byte
-
- MOV AL,[c_ctrl+bx] ;get control byte in AL
- TEST AL,00000001b ;is RTS handshake enabled?
- JZ ComRdX ;no, exit
-
-
- ; Check for RTS assert (Used <= RTSOn)
- ; Variable USED (# of used bytes in buffer) calculated as :
- ; IF (Head >= Tail) THEN
- ; Used = Head-Tail
- ; ELSE
- ; Used = BufferSize - (Tail-Head)
-
- SHL BL,1 ;BX <- Word array index
- CMP DI,SI ;Head >= Tail ?
- JAE ComRd5 ; Yes, use alternate formula
- SUB SI,DI ;SI <- Tail - Head
- MOV DI,[C_InSize+BX] ;DI <- Input buffer size
- ComRd5: SUB DI,SI ;DI <- Amount of buffer used
- CMP DI,[C_RTSOn+BX] ;Used > Limit ?
- JA ComRdX ; Yes, not ready for receive
-
- ; Here to assert RTS
-
- ADD DL,MCR ;DX <- 8250 MCR port address
- IN AL,DX ;AL <- 8250 MCR
- OR AL,00000010b ;Assert RTS
- NOP ;Slow down for slow machines
- NOP
- OUT DX,AL ;Send to port
- JMP ComRdX ;Exit
-
- ENDP ComReadCh
-
- ;********************************************************
- ;* *
- ;* Function ComReadChW(ComPort:Byte) : Char *
- ;* *
- ;********************************************************
-
- PROC ComReadChW FAR
-
- MOV BX,SP ;BX <- Stack pointer
- MOV AL,[SS:BX+4] ;AL <- Port #
-
- dec al ;Adjust port number (COM1=0)
- xor bh,bh ;Nuke BH
- mov bl,al ;Get byte index into BL
- shl bl,1 ;Convert to word index
- mov dx,[C_Portaddr+BX] ;Get port base address
- shr bl,1 ;Convert back to byte index
-
- ; Wait for character
-
- ComRW1: MOV AH,[C_Status+BX] ;AL <- Status byte
- TEST AH,00000001b ;Input buffer empty ?
- JNZ ComRW1 ; Yes, continue waiting
-
- CLI ;Disable interrupts
- JMP ComRd2 ;Proceed with normal read
-
- ENDP ComReadChW
-
- ;********************************************************
- ;* *
- ;* Procedure ComWriteCh(ComPort:Byte; Var Ch:Char) *
- ;* *
- ;********************************************************
-
- PROC ComWriteCh FAR
-
- ; Check port # for validity
-
- MOV BX,SP ;Point BX at parameters
- MOV AL,[SS:BX+6] ;AL <- Port #
- MOV CH,[SS:BX+4] ;CH <- Character to send
-
- dec al ;Adjust port number (COM1=0)
- xor bh,bh ;Nuke BH
- mov bl,al ;Get byte index into BL
- shl bl,1 ;Convert to word index
- mov dx,[C_Portaddr+BX] ;Get port base address
- shr bl,1 ;Convert back to byte index
-
- mov ah, [c_status+bx] ;get status word for PUTCHAR
-
- CLI ;Disable interrupts
- PutChar ;Place character in buffer (AL nuked)
- STI ;Enable interrupts
-
- ComWr1: RET 4 ;Exit
-
- ENDP ComWriteCh
-
- ;********************************************************
- ;* *
- ;* Procedure ComWriteChW(ComPort:Byte; Var Ch:Char) *
- ;* *
- ;********************************************************
-
- PROC ComWriteChW FAR
-
- ; Check port # for validity
-
- MOV BX,SP ;Point BX at parameters
- MOV AL,[SS:BX+6] ;AL <- Port #
- MOV CH,[SS:BX+4] ;CH <- Character to send
-
- dec al ;Adjust port number (COM1=0)
- xor bh,bh ;Nuke BH
- mov bl,al ;Get byte index into BL
- shl bl,1 ;Convert to word index
- mov dx,[C_Portaddr+BX] ;Get port base address
- shr bl,1 ;Convert back to byte index
-
- ; Wait for buffer to open up
-
- ComWW1: MOV AH,[C_Status+BX] ;AH <- Status byte
- TEST AH,00101000b ;Buffer filled ?
- JNZ ComWW1 ; Yes, loop until open
-
- CLI ;Turn off interrupts
- PutChar ;Place character in buffer (AL nuked)
- STI ;Enable interrupts
-
- ComWW2: RET 4 ;Exit
-
- ENDP ComWriteChW
-
- ;********************************************************
-
- ENDS CODE
- END
-